package com.gitee.wsl.mathematics.vector.vec3


import com.gitee.wsl.ext.array.DoubleArray

import com.gitee.wsl.io.dataproxy.DataProxy
import com.gitee.wsl.io.dataproxy.asProxy
import com.gitee.wsl.mathematics.coordinate.d3.MutableCoordinate3D
import com.gitee.wsl.mathematics.vector.ext.dot
import com.gitee.wsl.mathematics.vector.ext.times
import com.gitee.wsl.mathematics.vector.vec4.MutableVec4
import com.gitee.wsl.mathematics.vector.vec2.MutableVec2
import kotlin.math.*

/**
 * A class representing a three-dimensional / spatial vector.
 */
open class MutableVec3(override val proxy: DataProxy<Double>  ):Vec3(proxy=proxy),
    MutableCoordinate3D<Vec3>{
    constructor(x: Double=0.0,
                    y: Double=0.0,
                    z: Double=0.0):this(DoubleArray(x,y,z).asProxy())
    constructor(a: Number) : this(a.toDouble(), a.toDouble(), a.toDouble())
    constructor(x: Number, y: Number, z: Number) : this(x.toDouble(), y.toDouble(), z.toDouble())
    constructor(base: Vector3D<*>) : this(base.x, base.y, base.z)
    constructor(base: Vector3<*,*>) : this(base.x, base.y, base.z)

    override val self
        get() = this

    //override val xy get() = MutableVec2(x, y)
    //override val xz get() = MutableVec2(x, z)
    //override val yz get() = MutableVec2(y, z)

    //override val vec2 get() = MutableVec2(x, y)
    //override val vec3 get() = this
    override val vec4 get() = MutableVec4(x, y, z, 0.0)

    override fun createVec2(a: Double, b: Double) = MutableVec2(x,y)

    override fun create(x: Double, y: Double, z: Double): MutableVec3 = MutableVec3(x, y, z)

    companion object {
        val one get() = MutableVec3(1.0, 1.0, 1.0)
        val zero get() = MutableVec3(0.0, 0.0, 0.0)
        val right get() = MutableVec3(1.0, 0.0, 0.0)
        val left get() = MutableVec3(-1.0, 0.0, 0.0)
        val up get() = MutableVec3(0.0, 1.0, 0.0)
        val down get() = MutableVec3(0.0, -1.0, 0.0)
        val forward get() = MutableVec3(0.0, 0.0, 1.0)
        val backward get() = MutableVec3(0.0, 0.0, -1.0)
        val negativeInfinity get() = MutableVec3(Double.NEGATIVE_INFINITY)
        val positiveInfinity get() = MutableVec3(Double.POSITIVE_INFINITY)

        val UNIT_X = MutableVec3(1f, 0f, 0f)
        val UNIT_Y = MutableVec3(0f, 1f, 0f)
        val UNIT_Z = MutableVec3(0f, 0f, 1f)
    }


    override fun equals(other: Any?) = other is MutableVec3 && x == other.x && y == other.y && z == other.z
    override fun hashCode(): Int {
        var result = super.hashCode()
        result = 31 * result + x.hashCode()
        result = 31 * result + y.hashCode()
        result = 31 * result + z.hashCode()
        return result
    }

}


fun MutableVec3.Companion.refract(uv: MutableVec3, n: MutableVec3, etaiOverEtat: Double): Vec3 {
    val cosTheta = minOf(-uv.dot(n), 1.0)
    val rOutPerp = etaiOverEtat * (uv + cosTheta * n)
    val rOutParallel = -sqrt(abs(1.0 - rOutPerp.squaredLength)) * n

    // TODO: なぜか想定通りの値が算出されておらず一時的に「-」にしてある
    return rOutPerp - rOutParallel
}

